/**
 * 
 */
package co.fitstart.coach.web.resolver;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.MethodParameter;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;
import org.springframework.web.util.WebUtils;

import com.demo2do.core.cache.handler.CacheHandler;

import co.fitstart.coach.entity.security.Login;

/**
 * @author lute
 *
 */
public class WechatSecurityArgumentResolver implements HandlerMethodArgumentResolver {

    private static final Logger logger = LoggerFactory.getLogger(WechatSecurityArgumentResolver.class);

    @Autowired
    private CacheHandler coachCacheHandler;

    private String useridKey;
    
    /**
     * @param useridKey the useridKey to set
     */
    public void setUseridKey(String useridKey) {
        this.useridKey = useridKey;
    }
    
    /* (non-Javadoc)
     * @see org.springframework.web.method.support.HandlerMethodArgumentResolver#supportsParameter(org.springframework.core.MethodParameter)
     */
    public boolean supportsParameter(MethodParameter parameter) {
        return parameter.hasParameterAnnotation(Secure.class);
    }

    /* (non-Javadoc)
     * @see org.springframework.web.method.support.HandlerMethodArgumentResolver#resolveArgument(org.springframework.core.MethodParameter, org.springframework.web.method.support.ModelAndViewContainer, org.springframework.web.context.request.NativeWebRequest, org.springframework.web.bind.support.WebDataBinderFactory)
     */
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
        
        Secure secure = parameter.getParameterAnnotation(Secure.class);
        
        // Step1 Get cache key from cookie & check
        String cachekey = this.getCacheKey(secure, webRequest);
        
        if(!StringUtils.isNoneBlank(cachekey)) {
            return null;
        }
        
        // Step2 Get login info from cache by cache key & check
        Login login = this.getCacheLogin(cachekey);
        
        if(login == null) {
            return null;
        }
        
        
        String property = secure.property();
        
        if (property != null && property.equals("id")) { 
            
            // @secure get property id
            return login.getId();
            
        }else if(StringUtils.isBlank(property) && parameter.getParameterType().isAssignableFrom(login.getClass())) {
            
            // @secure get login object
            return login;
        }else {
            
            // @secure not mapped login object & Extract property using BeanWrapperImpl
            try {
                
                BeanWrapperImpl wrapper = new BeanWrapperImpl(login);
                
                return wrapper.getPropertyValue(property);
                
            } catch (BeansException be) {
                
                logger.error("WechatSecurityArgumentResolver#resolveArgument() - Error when extracting property [{}] from security object [{}].", property, login);
            }
        }
        
        return null;
    }
    
    /**
     * Get cache key from cookie
     * 
     * @param request
     * @param key
     * @return
     */
    private String getCacheKey(Secure secure, NativeWebRequest webRequest) {
        
        String key = this.useridKey;
        
        if (StringUtils.isNotBlank(secure.value())) {
            key = secure.value();
        }
        
        logger.trace("WechatSecurityArgumentResovler#resolveArgument() - Get openid key [{}].", key);
        
        // Transform NativeWebRequest to HttpServletRequest
        HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
        
        // Get openid cookie
        Cookie cookie = WebUtils.getCookie(request, useridKey);
        
        if(cookie != null) {
            
            logger.trace("#resolveArgument() get cache key ["+ cookie.getValue() +"] from cookie by cookie key [" + key + "]");
            
            return cookie.getValue();
        }
        
        logger.trace("#resolveArgument() can not get cache key from cookie");
        
        return null;
    }
    
    /**
     * Get login object from cache
     * 
     * @param cacheKey
     * @return
     */
    private Login getCacheLogin(String cacheKey) {
        
        Login login = coachCacheHandler.get(cacheKey, Login.class);
        
        if(login == null) {
            logger.trace("#resolveArgument() can not get login from cache by cacheKey[" + cacheKey + "]");
        }
        
        return login;
    }

}
